﻿using LibNiconico.NiconicoApi.Mylist;
using LibNiconico.NiconicoApi.Videos;
using NicoView.Model.Browser;
using NicoView.Model.Service;
using NicoView.Model.Service.Broadcast;
using NicoView.Model.Service.Errors;
using NicoView.Model.Service.Events;
using NicoView.Model.Service.Lives;
using NicoView.Model.Service.Property;
using NicoView.Model.Service.Results;
using NicoView.Model.Share.Service;
using NicoView.Model.Speech;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;

namespace NicoView.Model
{
    /// <summary>
    /// にこびゅアプリケーション
    /// </summary>
    public  class NicoViewApplication:NicoViewObservableObject
    {

        #region コンストラクタ
        static NicoViewApplication()
        {

        }

        /// <summary>
        /// コンストラクタ
        /// </summary>
        private NicoViewApplication()
        {


            SetRequest = null;
            Property = new NicoViewProperty();


            this.isloaded = false;
            SynchronizationContext = SynchronizationContext.Current;



            this.Instance = createServiceApplication();
        }

        #endregion

        #region イベント

        /// <summary>
        /// 認証情報設定リクエストイベント
        /// </summary>
        public event Action<NicoServiceRequieSetEventArgs> SetRequest;

        /// <summary>
        /// 警告イベント
        /// </summary>
        public event NicoWarningHandler Warning;

        /// <summary>
        /// 認証情報が設定されていない場合に呼び出されるイベント
        /// </summary>
        public event NicoServiceApplicationInstance.ServieceNotSet NotSetAuth;


        /// <summary>
        /// 認証不正時に呼び出されるハンドラ
        /// </summary>
        public event Action<NicoServiceRequieSetEventArgs> AuthFailed;

        #endregion

        #region プロパティ・メンバ

        /// <summary>
        /// 割り当てられた同期コンテキスト
        /// </summary>
        public SynchronizationContext SynchronizationContext { get; private set; }

        /// <summary>
        /// にこびゅプロパティ
        /// </summary>
        public NicoViewProperty Property { get; private set; }

        /// <summary>
        /// このアプリケーションが有効か判定
        /// </summary>
        public bool IsEnabled
        {
            get
            {

                return this.IsLoaded;
            }
        }

        /// <summary>
        /// このアプリケーションがロードされた状態か判定
        /// </summary>
        public bool IsLoaded
        {
            get
            {
                return this.isloaded;
            }

            set
            {
                this.Set(() => this.IsLoaded, ref this.isloaded, value);
                this.RaisePropertyChanged(() => this.IsEnabled);
            }
        }

        private bool isloaded;

        /// <summary>
        /// 割り当てられたインスタンス
        /// </summary>
        public static readonly NicoViewApplication Current = new NicoViewApplication();

        /// <summary>
        /// サービスインスタンス
        /// </summary>
        public NicoServiceApplicationInstance Instance
        {
            get;
            private set;
        }

        /// <summary>
        /// 動画URL正規表現
        /// </summary>
        private static readonly Regex videoUrlRegex = new Regex(@"(http://)(www.)?(nicovideo.jp/watch/)(?<videoId>" + NicoFormat.VIDEOID_FORMAT + ").*");

        #endregion

        #region メソッド




        /// <summary>
        /// 認証情報呼び出し時の動作
        /// </summary>
        /// <param name="e"></param>
        internal void OnSetRequest(NicoServiceRequieSetEventArgs e)
        {
            
            if (SetRequest != null) SetRequest(e);
        }

        /// <summary>
        /// このアプリケーションの初期化
        /// </summary>
        /// <returns></returns>
        public async Task InitializeAsync()
        {

            await Property.PropertysLoadAsync().ConfigureAwait(false);
            this.Instance.Auth.Auth = this.Property.Auth;
            Browsers.Instance.SetCurrenttUrlExecuteBrowser(this.Property.UrlExecuteBrowser);

        }


        /// <summary>
        /// 非同期にユーザ設定を読込
        /// </summary>
        /// <returns></returns>
        internal async Task UserDataLoadAsync()
        {
            lock (this)
            {
                if (this.IsLoaded) { return; }
            }

            await Property.UserDataLoadAsync().ConfigureAwait(false);

            lock (this)
            {
                IsLoaded = true;
            }



        }

        /// <summary>
        /// このインスタンスが読み込まれたときに実行されるメソッド
        /// </summary>
        public async Task LoadAsync()
        {
            await this.UserDataLoadAsync();
            await this.Instance.AuthenticateAsync();
           
        }

        /// <summary>
        /// 非同期に終了処理を行う
        /// </summary>
        /// <returns></returns>
        public async Task FinalizeAsync()
        {
            lock (this)
            {
                if (!this.IsLoaded) { return; }
            }


            await this.Property.SaveAsync(this.Instance.Auth.Auth).ConfigureAwait(false);
        }
        
        /// <summary>
        /// 警告の通知
        /// </summary>
        /// <param name="e"></param>
        /// <param name="message"></param>
        internal void OnNotifyWaning(Exception e, string message)
        {
            OnNotifyWaning(new NicoWarningEventArgs(e, message));
        }

        /// <summary>
        /// 警告の通知
        /// </summary>
        /// <param name="e"></param>
        internal void OnNotifyWaning(NicoWarningEventArgs e)
        {
            SynchronizationContext.Send((args) =>
            {
                if (Warning != null) Warning(e);
            }, null);
        }




        
        /// <summary>
        /// サービスアプリケーションインスタンスを生成
        /// </summary>
        /// <returns></returns>
        private NicoServiceApplicationInstance createServiceApplication()
        {
            var application = new NicoServiceApplicationInstance(this);


            return application;
        }




        


        internal NicoUserAuth OnServieceNotSet()
        {


            if (NotSetAuth != null)
            {
                NicoUserAuth auth = null;
                var eventArgs = new NicoServiceRequieSetEventArgs("ユーザ認証情報が登録されていません\r\nツールを使用するにはユーザ認証情報登録が必要です");
                eventArgs.OnSet += args =>
                {
                    auth = args.Auth;
                    
                };
                NotSetAuth(eventArgs);

                return auth;
            }

            return null ;

        }

        #region URL解決
        /// <summary>
        /// URLの解決
        /// </summary>
        /// <param name="url"></param>
        public void ExecuteUrl(string url)
        {
            executeUrl(url);
        }


        private void executeUrl(string url)
        {

            Browsers.Instance.CurrentUrlExecuteBrowser.ExecuteUrl(url);


        }


        public void ExecuteVideoUrl(string videoId)
        {
            executeUrl("http://www.nicovideo.jp/watch/" + videoId);
        }

        public void ExecuteLiveUrl(string liveId)
        {
            executeUrl("http://live.nicovideo.jp/watch/" + liveId);
        }

        public void ExecuteCommunityUrl(string communityId)
        {
            executeUrl("http://com.nicovideo.jp/community/" + communityId);
        }


        public void ExecuteUserInfoUrl(string userId)
        {
            executeUrl("http://www.nicovideo.jp/user/" + userId);
        }

        #endregion


        /// <summary>
        /// 認証不正時の動作
        /// </summary>
        /// <param name="eventArgs"></param>
        internal void OnFailAuth(NicoServiceRequieSetEventArgs eventArgs)
        {
            if (AuthFailed != null)
            {
                this.AuthFailed(eventArgs);
            }
        }

        #endregion
    }
}
